/**
 * 
 */
package qy.jalgotrade.technical;

import java.time.ZonedDateTime;
import java.util.Map;

import qy.jalgotrade.dataseries.SequenceDataSeries;
import qy.jalgotrade.event.EventHandler;

/**
 * <pre>
 * An EventBasedFilter class is responsible for capturing new values in a :class:`pyalgotrade.dataseries.DataSeries`
 * and using an :class:`EventWindow` to calculate new values.
 * pyalgotrade.technical.EventBasedFilter: 使用一个 pyalgotrade.technical.EventWindow 的实现类计算指标, 并保存在一个
 * pyalgotrade.dataseries.DataSeries 中, 当 eventWindow 有新 value 时, 自动计算指标并更新 dataSeries;
 * EventBasedFilter 实现类继承自 pyalgotrade.dataseries.SequenceDataSeries
 * </pre>
 * 
 * <pre>
 * T: Type for SequenceDataSeries
 * U: input for EventWindow
 * V: output for EventWindow
 * </pre>
 * 
 * @author c-geo
 *
 */
public class EventBasedFilter<T> extends SequenceDataSeries<T> implements EventHandler {

	private SequenceDataSeries __dataSeries;

	private EventWindow __eventWindow;

	/**
	 * 
	 * @param dataSeries  The DataSeries instance being filtered.
	 * @param eventWindow The EventWindow instance to use to calculate new values.
	 * @throws Exception
	 */
	public EventBasedFilter(SequenceDataSeries dataSeries, EventWindow eventWindow) throws Exception {

		this(dataSeries, eventWindow, 0);
	}

	/**
	 * 
	 * @param dataSeries  The DataSeries instance being filtered.
	 * @param eventWindow The EventWindow instance to use to calculate new values.
	 * @param maxLen      The maximum number of values to hold. Once a bounded length is full, when new
	 *                    items are added, a corresponding number of items are discarded from the
	 *                    opposite end. If None then dataseries.DEFAULT_MAX_LEN is used.
	 * @throws Exception
	 */
	public EventBasedFilter(SequenceDataSeries dataSeries, EventWindow eventWindow, int maxLen) throws Exception {

		super(maxLen);
		__dataSeries = dataSeries;
		// 订阅 pyalgotrade.feed.BaseFeed 的 new value 可用事件 (getNewValuesEvent()):
		__dataSeries.getNewValueEvent().subscribe(this);
		__eventWindow = eventWindow;
	}

	/**
	 * XXX: Java requires calling super() at the entry of sub class constructor. Only used by sub
	 * classes.
	 */
	protected EventBasedFilter(int maxLen) throws Exception {

		super(maxLen);
	}

	/**
	 * XXX: Java requires calling super() at the entry of sub class constructor. Only used by sub
	 * classes.
	 */
	protected void _init(SequenceDataSeries dataSeries, EventWindow eventWindow) {

		__dataSeries = dataSeries;
		// 订阅 pyalgotrade.feed.BaseFeed 的 new value 可用事件 (getNewValuesEvent()):
		__dataSeries.getNewValueEvent().subscribe(this);
		__eventWindow = eventWindow;
	}

	/* 
	 * (non-Javadoc)
	 * @see qy.jalgotrade.event.EventHandler#handle(java.lang.String, java.util.Map)
	 */
	@Override
	public void handle(String eventName, Map<String, Object> params) throws Exception {

		SequenceDataSeries<T> dataSeries = (SequenceDataSeries<T>) params.get("dataSeries");
		ZonedDateTime dateTime = (ZonedDateTime) params.get("dateTime");
		Object value = params.get("value");
		__onNewValue(dataSeries, dateTime, value);
	}

	/**
	 * 
	 * @param dataSeries
	 * @param dateTime
	 * @param value
	 * @throws Exception
	 */
	private void __onNewValue(SequenceDataSeries dataSeries, ZonedDateTime dateTime, Object value) throws Exception {

		// Let the event window perform calculations.
		__eventWindow.onNewValue(dateTime, value);
		// Get the resulting value
		@SuppressWarnings("unchecked")
		T newValue = (T) __eventWindow.getValue();
		// Add the new value.
		appendWithDateTime(dateTime, newValue);
	}

	/**
	 * 
	 * @return
	 */
	public EventWindow getEventWindow() {

		return __eventWindow;
	}

	/**
	 * 
	 * @return
	 */
	public SequenceDataSeries getDataSeries() {

		return __dataSeries;
	}
}
